﻿//////////////////////////////////////
// Authors: Dennis van der Werf, Martijn van Aalst
// Current Version: 1.3
//
// Version 1.0: Start up
// Version 1.1: Some tweaking 
// Version 1.2: Performance optimization
// Version 1.3: Colorfilter tweaking

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;


namespace KentekenHerkenning
{
    class LocateLicensePlate
    { 
        public Bitmap DoAlgorithm(Bitmap sourceImage)
        {
            const int widthtolerance = 5;
            const int heighttolerance = 3;

            Bitmap returnImage = new Bitmap(sourceImage);


            //Lockbits
            Rectangle rect = new Rectangle(0, 0, returnImage.Width, returnImage.Height);
            BitmapData returnImageDate = returnImage.LockBits(rect, ImageLockMode.ReadWrite, returnImage.PixelFormat);
            IntPtr pointer = returnImageDate.Scan0;// Lock Bits and get a pointer to the first Byte.
            int Size = Math.Abs(returnImageDate.Stride) * returnImage.Height; // Number of Bytes

            byte[] sourceImageArray = new Byte[Size];

            // Calculate the bytes per pixel
            int Bytespp = (returnImageDate.Stride / returnImage.Width);
            double offset = 2.2;

            // initialize some variables to boost performance
            int width = sourceImage.Width;
            int height = sourceImage.Height;
            byte zero = Convert.ToByte(0);
            byte max = Convert.ToByte(253);

            Marshal.Copy(pointer, sourceImageArray, 0, Size); // Copy Bitmap into the Byte array


            for (int i = 0; i < (Size - Bytespp); i += Bytespp)// Edit every pixel skip every Alpha Byte
            {
                // Enhance greens and set all none yellows to black
                if (sourceImageArray[i + 1] > sourceImageArray[i + 2])
                {
                    if (sourceImageArray[i] * 1.5 > 255) { sourceImageArray[i] = 255; }
                    else { sourceImageArray[i] = Convert.ToByte(sourceImageArray[i] * 1.5); }
                }
                else if (sourceImageArray[i + 1] > sourceImageArray[i + 2])
                {
                    if (sourceImageArray[i] * 0.5 < 0) { sourceImageArray[i] = 0; }
                    else { sourceImageArray[i] = Convert.ToByte(sourceImageArray[i] * 0.5); }
                }

                if ((sourceImageArray[i] * offset < sourceImageArray[i + 1] && sourceImageArray[i] * offset < sourceImageArray[i + 2]) == false)
                {
                    sourceImageArray[i] = zero;
                    sourceImageArray[i + 1] = zero;
                    sourceImageArray[i + 2] = zero;
                }

                // If the red pixelvalue is lower than 165 the pixel is not yellow.
                if (sourceImageArray[i + 2] < 165)
                {
                    sourceImageArray[i] = zero;
                    sourceImageArray[i + 1] = zero;
                    sourceImageArray[i + 2] = zero;
                }
                // If 180% of the Greenvalue is lower than the red pixelvalue, the pixel is not yellow.
                if (sourceImageArray[i + 1] * 1.8 < sourceImageArray[i + 2])
                {
                    sourceImageArray[i] = zero;
                    sourceImageArray[i + 1] = zero;
                    sourceImageArray[i + 2] = zero;
                }

            }

            Marshal.Copy(sourceImageArray, 0, pointer, Size); //Copy Array back into the Bitmap
            returnImage.UnlockBits(returnImageDate); // Unlock the bits

            // Count all the none black pixels for every x and y
            int x = 0;
            int y = 0;
            int set = 0;
            int[] Xlist = new int[width];
            int[] Ylist = new int[height];
            for (int i = 0; i < (Size - Bytespp); i += Bytespp)
            {
                // If the red value is higher than 0 it's yellow.
                if (sourceImageArray[i + 2] > 0)
                {
                    Ylist[y]++;
                    set++;
                }
                x++;
                if (x - width >= 0)
                {
                    x = 0;
                    y++;
                }
            }

            int mostPixels = 0;

            // find the y with the highest number of yellowpixels 
            for (int i = 0; i < height - 1; i++)
            {
                if (mostPixels < Ylist[i])
                {
                    mostPixels = Ylist[i];
                    y = i;

                }
            }


            int lpheight = y;


            //find the y for the upperright corner
            while (y > heighttolerance)
            {
                if (Ylist[y] < 1 && Ylist[y - heighttolerance] == 0 || y == 0)
                {
                    break;
                }
                y--;
            }

            // find the y for the lowerleft corner
            while (lpheight < height)
            {
                if (Ylist[lpheight] < 2)
                {
                    break;
                }
                lpheight++;
            }
            lpheight -= y;

            x = 0;
            for (int i = y * returnImageDate.Stride; i < (y + lpheight) * returnImageDate.Stride; i += Bytespp)
            {
                if (sourceImageArray[i + 2] > 0)
                {
                    Xlist[x]++;
                    set++;
                }
                x++;
                if (x - width >= 0)
                {
                    x = 0;
                }
            }

            mostPixels = 0;
            // find the x with the highest number of yellowpixels 
            for (int i = 0; i < width - 1; i++)
            {
                if (mostPixels < Xlist[i])
                {
                    mostPixels = Xlist[i];
                    x = i;
                }

            }
            int lpwidth = x;

            // find the x for the upperright corner
            while (x > widthtolerance)
            {
                if (Xlist[x] < 1 && Xlist[x - widthtolerance] == 0 || x == 0)
                {
                    break;
                }
                x--;
            }
            int empty = 0;

            //find the x for the lowerleft corner
            while (lpwidth < width - widthtolerance)
            {
                if (Xlist[lpwidth] <= 1 && Xlist[lpwidth + widthtolerance] == 0)
                {
                    if (empty > widthtolerance)
                    {
                        break;
                    }
                    empty++;
                }

                lpwidth++;
            }
            lpwidth -= x;


            Point upperleft = new Point();
            upperleft.X = x;
            upperleft.Y = y;

            // If no useable content is found return 1 pixel.
            if (upperleft.X + 1 > width)
            {
                upperleft.X -= 1;
            }
            if (upperleft.Y + 1 > height)
            {
                upperleft.Y -= 1;
            }

            Size lpSize = new Size();
            if (lpwidth == 0)
            {
                lpwidth = 1;
            }
            lpSize.Width = lpwidth - widthtolerance;
            if (lpheight == 0)
            {
                lpheight = 1;
            }
            lpSize.Height = lpheight;

            // Copy the licenseplate out of the originale bitmap and return the licenseplate
            Rectangle licenseplateRec = new Rectangle(upperleft, lpSize);
            Bitmap licenseplate = sourceImage.Clone(licenseplateRec, sourceImage.PixelFormat);

            return licenseplate;
        }
    }
}

